import { MapInfo } from "../game/map/MapInfo";
import EditorMap from "./EditorMap";

 
/**
 * 编辑器寻路工具  导出数据
 */
export enum MOVE_TYPE {
    None = 0,
    ADD = 1,
    DEL = 2,
}
export enum MODE_TYPE {
    ZHANGAI = 0,
    NONE = 1,
}
 
const {ccclass, property} = cc._decorator;
@ccclass("pathFind") 
export default class PathFindEditor extends cc.Component { 
    @property({type:cc.Integer,tooltip:"格子单位大小"})
    gx:number = 100; 
    @property({type:cc.Graphics,tooltip:"画笔"})
    g:cc.Graphics = null; 
    pathObj:any = null; 
    nx:number = 0;
    startPoint:cc.Vec2 = null;
    endPoint:cc.Vec2 = null;
    Total:number = -1;
    moveType:number = MOVE_TYPE.None;
    //List<Point>
    path:Array<cc.Vec2> = null;
    mapArr:{} = null;

    //当前模式
    modeType:number = MODE_TYPE.NONE;

    editor:EditorMap = null;

    //搜索上限
    findMax:number = 0;
    onLoad () {
        this.g = this.g || this.node.addComponent(cc.Graphics);
        this.Init();  
    }

    setEdit(editor:EditorMap){
        this.editor = editor;
    }

    Init(){
        this.pathObj={}; 
        this.nx = 0
        this.startPoint=cc.v2(0,3);
        this.endPoint=cc.v2(11,1);
        this.Total=-1;
        this.moveType = MOVE_TYPE.None;
        this.path=[];
        this.mapArr={};//Dictionary<string, MapInfo>
        this.findMax=500000;  
        this.editor.modeBtnText.string = "移动模式"
    }


    initData(json:MapData){
        //设置格子大小
        this.Init();
        this.gx = json.cellSize; 
        let r = new cc.Rect(cc.view.getVisibleOrigin().x,cc.view.getVisibleOrigin().y,this.node.width,this.node.height)
        let zx = 0;
        let yx = Math.ceil(r.width/this.gx);
        let zy = 0;
        let yy = Math.ceil(r.height/this.gx);

        //加载障碍物
        for (let i = zy; i < yy; i++){ 
            for (let a = zx; a < yx; a++){ 
                if (json.cells[i+"*"+a] != null){
                    //障碍物
                    this.pathObj[i+"*"+a] = 1; 
                }
            }
        }   
        this.search(); 
        this.Paint(); 
    }
  

    stageDowd(e){
        let pos =  this.node.convertToNodeSpaceAR(cc.v2(e.getLocationX(),e.getLocationY()))  
        let nx = Math.floor( pos.x/ this.gx), ny =Math.floor(pos.y / this.gx); 
        let id = ny + "*" + nx;  
        if (this.startPoint.x == nx && this.startPoint.y == ny)
        {
            this.moveType = 3;//更改开始点
        }else if (this.endPoint.x == nx && this.endPoint.y == ny)
        {
            this.moveType = 4;//更改结束点
        }
        else if (!this.pathObj[id])
        {
            this.moveType = 1;//添加 
        }else
        { 
            this.moveType = 2;//清除
        } 
        cc.Canvas.instance.node.on(cc.Node.EventType.MOUSE_UP,this.stageUp,this);
        cc.Canvas.instance.node.on(cc.Node.EventType.MOUSE_MOVE,this.stageMove,this);
    }

    stageUp(e){
        cc.Canvas.instance.node.off(cc.Node.EventType.MOUSE_UP,this.stageUp,this);
        cc.Canvas.instance.node.off(cc.Node.EventType.MOUSE_MOVE,this.stageMove,this);
        this.moveType = 0;
        this.search(); 
        this.Paint();  
        if(this.path.length <= 0){
            console.log("无解")
        }
        this.path =[];
    }

    stageMove(e){ 
        let pos =  this.node.convertToNodeSpaceAR(cc.v2(e.getLocationX(),e.getLocationY()))  
        let nx = Math.floor( pos.x/ this.gx), ny =Math.floor(pos.y / this.gx);
        let id = ny + "*" + nx; 
        if (this.moveType == 1)
            {
                if (this.pathObj[id] ==null)
                {
                    if((this.startPoint.y+"*"+this.startPoint.x)!=id&&(this.endPoint.y+"*"+this.endPoint.x)!=id){
                        this.pathObj[id] = 1;
                        this.Paint();
                    }
                }
            }
            else if (this.moveType == 2)
            { 
                if (this.pathObj[id] != null)
                {
                    delete(this.pathObj[id]);
                    this.Paint();
                }
            }else if (this.moveType == 3)
            {
                if (nx != this.startPoint.x || ny != this.startPoint.y)
                {
                    if (this.pathObj[id] == null)
                    {
                        this.startPoint.x = nx;
                        this.startPoint.y = ny;
                        this.Paint();
                    }
                }
            }
            else if (this.moveType == 4)
            {
                if (this.nx != this.endPoint.x || ny != this.endPoint.y)
                {
                    if (this.pathObj[id] == null)
                    {
                        this.endPoint.x = nx;
                        this.endPoint.y = ny;
                        this.Paint();
                    }
                        
                }
            }
    }

    search(){
        if (this.pathObj[this.startPoint.y + "*" + this.startPoint.x] != null)
        {
            this.path = []//[v2];
            return;
        }
        this.mapArr={};
        let startNode = new MapInfo(this.startPoint.x, this.startPoint.y);
        let endNode = new MapInfo(this.endPoint.x, this.endPoint.y);
        let i, l, f,t,current,test,links;
        let openBase = Math.abs(this.startPoint.x - this.endPoint.x) + Math.abs(this.startPoint.y - this.endPoint.y);
        let open=[null,null];
        open[0] = startNode;
        startNode.version = true;
        startNode.nowCost= 0;
        let js = 0;
        while (true){
            js++;
            if (js >= this.findMax){
                //超出上限代表没找到
                this.path =[]; 
                console.log("没找到")
                return;
            }
            current = open[0];
            open[0] = current.next;
            if (open[0]!=null) open[0].pre = null;
            if (current.x == endNode.x&& current.y == endNode.y)
            {
                this.path = [];
                this.prunePath(startNode, current);
                return;
            }
            if (current.links == null){
                current.addLinks(this.mapArr,this.pathObj);
            }
            links = current.links;
            l = current.linksLength;
            for (i = 0; i < l; i++){
                test = links[i];//测试的四个面
                f = current.nowCost + 1;
                if (!test.version) {
                    test.version = true;
                    test.parent = current;
                    test.nowCost = f;
                    test.dist = Math.abs(this.endPoint.x - test.x) + Math.abs(this.endPoint.y - test.y);//到终点的距离
                    f += test.dist;
                    test.mayCost = f;//估计的消耗	
                    f = (f - openBase) >> 1;
                    test.pre = null;
                    test.next = open[f];//保存下一步
                    if (open[f]!=null) open[f].pre = test;
                    open[f] = test;
                }else{
                    if (test.pre!=null) test.pre.next = test.next;
                    if (test.next!=null) test.next.pre = test.pre;
                    if (open[1] == test) open[1] = test.next;
                           
                    test.parent = current;
                    test.nowCost = f;
                    test.mayCost = f + test.dist;//加下终点绝对值
                    test.pre = null;
                    test.next = open[0];
                    if (open[0]!=null) open[0].pre = test;
                    open[0] = test;
                }
            }
            if (open[0]==null)
            {
                if (open[1] == null){ 
                    break;
                } 
                t = open[0];
                open[0] = open[1];
                open[1] = t;
                openBase += 2;
            }
        } 
    }

    prunePath(startNode, endNode){
        if (this.startPoint.x == this.endPoint.x&&this.startPoint.y==this.endPoint.y) return;
        let current = endNode;
        let dx = current.x - endNode.x;
        let dy = current.y - endNode.y;
        let cx,cy,t,t2;
        
        while (true){
            if (current.x == startNode.x&& current.y == startNode.y){
                this.path[this.path.length]=cc.v2(current.x,current.y);
                return;
            }
            t = current.parent;
            cx = current.x;
            cy = current.y;
            if (t != startNode){
                t2 = t.parent;
                if (Math.abs(t2.x - cx) == 1 && Math.abs(t2.y - cy) == 1 && this.pathObj[cy +"*"+ t2.x] ==null && this.pathObj[t2.y +"*"+ cx]== null)
                {
                    t = t2;
                }
            }
            if (t.x - cx == dx && t.y - cy == dy)
            {
                    current = t;
            }else
            {
                dx = t.x - cx;
                dy = t.y - cy;
                this.path[this.path.length]=cc.v2(current.x,current.y);
                current = t;
            }
        }
    }

    Paint(init:boolean = true){ 
        this.g.clear();
        let r=new cc.Rect(cc.view.getVisibleOrigin().x,cc.view.getVisibleOrigin().y,this.node.width,this.node.height)
        let zx = 0;
        let yx = Math.ceil(r.width/this.gx);
        let zy = 0;
        let yy = Math.ceil(r.height/this.gx); 
        this.fillRect(cc.color(0, 255, 100),this.gx * this.startPoint.x, this.gx * this.startPoint.y, this.gx, this.gx);
        this.fillRect(cc.color(255,0,0),this.gx * this.endPoint.x, this.gx * this.endPoint.y, this.gx, this.gx);
        if(init){
            for (let i = zy; i < yy; i++){
                for (let a = zx; a < yx; a++){
                    if (this.pathObj[i+"*"+a] != null){
                        //障碍物
                        this.fillRect(cc.color(100,100,100),this.gx * a , this.gx * i , this.gx, this.gx,5);
                    }
                    this.g.strokeColor = cc.color(150,150,150);
                    this.g.rect(this.gx * a , this.gx * i , this.gx, this.gx);
                    this.g.lineWidth = 5;
                    this.g.stroke();

                    //防止重复创建lable
                    if(this.node.getChildByName(`${a},${i}`) == null){
                        let node = new cc.Node(`${a},${i}`);
                        let lab = node.addComponent(cc.Label)
                        lab.string = `${a},${i}`;
                        lab.node.color = cc.Color.RED
                        lab.node.parent = this.node;
                        lab.node.x = this.gx * a  + this.gx/2
                        lab.node.y = this.gx * i + this.gx/2
                        lab.cacheMode = cc.Label.CacheMode.CHAR;
                    }  
                }
            }
        }
        if (this.path != null){
            if (this.path.length > 1){
                let b = this.gx / 2;
                let p = new Array(this.path.length);
                this.g.strokeColor = cc.Color.BLUE; 
                this.g.moveTo(this.path[0].x * this.gx+ b, this.path[0].y * this.gx + b);
                for(let i = 1; i < p.length; i++){
                  this.g.lineTo(this.path[i].x * this.gx+ b, this.path[i].y* this.gx + b);
                }
                this.g.stroke();
            }
        } 
    }

    fillRect(c,x,y,w,h,store:number = 1){ 
        this.g.rect(x,y,w,h);
        this.g.fillColor =c; 
        this.g.lineWidth= store
        this.g.fill(); 
    }
     
    getMapData(){ 
        //打印地图信息
        let r = new cc.Rect(cc.view.getVisibleOrigin().x,cc.view.getVisibleOrigin().y,this.node.width,this.node.height)
        let zx = 0;
        let yx = Math.ceil(r.width/this.gx);
        let zy = 0;
        let yy = Math.ceil(r.height/this.gx);  
        let mapInfo = {cells:null,cellSize:this.gx ,mapSize:{width:this.node.width,height:this.node.height}}
        let cells = {};
        for (let i = zy; i < yy; i++){ 
            for (let a = zx; a < yx; a++){ 
                if (this.pathObj[i+"*"+a] != null){
                    //障碍物
                    cells[i+"*"+a] = 1; 
                }
            }
        }
        mapInfo.cells = cells;
        return mapInfo;
    }

    


    onZhangAi(){
        if(this.modeType == MODE_TYPE.NONE){
            this.modeType = MODE_TYPE.ZHANGAI; 
            this.editor.modeBtnText.string = "障碍模式"
            cc.Canvas.instance.node.on(cc.Node.EventType.MOUSE_DOWN,this.stageDowd,this); 
        }else{ 
            this.editor.modeBtnText.string = "移动模式"
            this.modeType = MODE_TYPE.NONE;
            cc.Canvas.instance.node.off(cc.Node.EventType.MOUSE_DOWN,this.stageDowd,this); 
        } 
    }
}
